﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OVS.BusinessObjects;
using OVS.BLL;
using log4net;
using OVS_ApplicationConfiguration.Manager;
using System.Windows;
using System.Collections;
using System.Windows.Controls;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.UI;
using System.Threading;
using MjpegProcessor;
using Emgu.CV.GPU;
using System.Diagnostics;
using OVS_Tools;
using OVS_FormsRecognition.Objects;
using System.IO;
using Cudafy
;
using Cudafy.Host;
using Cudafy.Translator;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Threading;


namespace OVS_FormsRecognition.Manager
{
    /// <summary>
    /// Manager permetant de gérer la détection d'objet dans une caméra
    /// </summary>
    public class FramFromCamManager
    {
        #region Attr Logger
        /// <summary>
        /// Logger par défaut du ManagerUtilisateurs
        /// </summary>
        private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(typeof(FormsRecognitionManager));

        Dictionary<int, CameraFromMjpegDecoder> listCamera;


        #endregion

        #region Attributs
        private int counter;
        #endregion

        #region Gestion du singleton

        /// <summary>
        /// Instance locale pour héberger le singleton
        /// </summary>
        static FramFromCamManager instance = null;

        /// <summary>
        /// Objet permettant la gestion des LOCK lors de l'instanciation
        /// </summary>
        static readonly object padlock = new object();

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        FramFromCamManager()
        {
            if (_Log.IsDebugEnabled)
                _Log.DebugFormat("Nouvelle instance de '{0}'", this.GetType().ToString());

        }

        /// <summary>
        /// Déclaration unique par gestion du singleton
        /// </summary>
        public static FramFromCamManager Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new FramFromCamManager();
                    }
                    return instance;
                }
            }
        }

        #endregion Gestion du singleton

        /// <summary>
        /// News the frame allow from camera.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        public void NewFrameAllowFromCamera(object sender, EventArgs e)
        {

            CameraFromMjpegDecoder camera = e as CameraFromMjpegDecoder;
            
            //if (camera.FramCounter == 1)
            {
                camera.currentFrame = (Bitmap)camera.MjpegDecoder.Bitmap.Clone();
                PushFramToThreadPool(camera);
                camera.FramCounter = 0;
                camera.isNewFrame = true;
            }
            //camera.FramCounter++;

        }

        /// <summary>
        /// Pushes the fram to thread pool.
        /// </summary>
        /// <param name="camera">The camera.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        private void PushFramToThreadPool(CameraFromMjpegDecoder camera)
        {
            lock (this)
            {
                int maxNumberOfThread = 35;

                if (camera.pool == null)
                {
                    //camera.currentThreadIdInPool = 0;
                    camera.pool = new Dictionary<int, ThreadDetecor>();

                }
                if (camera.pool.Count >= maxNumberOfThread)
                {
                    //_Log.Debug("Wait for new Thread: camId: " + camera.CameraId);
                    List<int> threadToRemove = new List<int>();
                    foreach (KeyValuePair<int, ThreadDetecor> item in camera.pool)
                    {
                        if (item.Value.isFinished)
                        {
                            threadToRemove.Add(item.Key);
                        }
                    }
                    foreach (int key in threadToRemove)
                    {
                        camera.pool.Remove(key);
                    }

                }

                ////// Asynchrone           
                //ThreadDetecor threaCam = new ThreadDetecor(counter);
                //threaCam.Start(camera);
                //camera.pool.Add(camera.counter, threaCam);
                //camera.counter++;
                //camera.currentThreadIdInPool++;


                // Synchrone
                new ThreadDetecor(counter).ProcessFrame(camera);
                camera.counter++;
                camera.currentThreadIdInPool++;
            }
        }

        public static void ProcessAllCamInParalell(List<CameraFromMjpegDecoder> listCamEnable)
        {

            //List<CameraFromMjpegDecoder> camRefreshList = new List<CameraFromMjpegDecoder>();
            //foreach (CameraFromMjpegDecoder cam in listCamEnable)
            //{
            //    if (cam.isNewFrame == true)
            //    {
            //        camRefreshList.Add(cam);
            //        cam.isNewFrame = false;
            //    }

            //}

            //Parallel.ForEach(listCamEnable, camera =>
            //           {                           
            //                   ThreadDetecor.ProcessFrame(camera);                           
            //           });
        }



    }
}
